package com.maixy.rabbitmqdemo.normal;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName RabbitConfig
 * @Description RabbitMQ配置类
 *  总结：2019年12月28日 17点01分 就目前的学习到的RabbitMQ知识进行总结
 *  直连模式:生产者和消费者一对一的模式，即生产者产生信息，消费者接收信息
 *  Work queues：当消息处理比较耗时时，可能生产消息的速度远远大于消息消费的速度，消息就会堆积的原来越多，
 *              无法及时处理，此时就可能使用work模型，让多个消费者绑定到一个队列，共同消费队列中的消息。
 *              队列中消息一旦被消费就会消失，此时任务是不会被重复执行。
 *              默认情况下，RabbitMQ将按顺序将每个消息发送给下一个使用者，平均而言，每个消费者都会受到相同数量的消息，
 *              这种分发方式称为循环
 *  Fanout模式（发布/订阅模式）:1.可以有多个消费者
 *                           2.每个消费者有自己的queue（队列）
 *                           3.每个队列要绑定到Exchange（交换机）
 *                           4，生产者发送消息，只能发送到交换机，交换机来决定要发给那个队列，生产者无法决定
 *                           5.交换机把消息发送给所有绑定过的队列
 *                           6.队列的消费者都能拿到消息。实现一条消息被多个消费者消费
 *  Routing之订阅模型-Direct(直连)：在fanout模式中，一条消息会被所有的队列都消费，但是在某些场景下，我们希望不同的消息被不同的队列消费，
 *                                这时就要用到Direct模式的Exchange
 *                                1.队列与交换机的绑定不能是任意绑定了，而是指定一个RoutingKey（路由key）
 *                                2.消息的发送方向Exchange发送消息是必须指定消息的RoutingKey。
 *                                3.Exchange不再把消息交给每个绑定的队列，而是根据消息RoutingKey进行判断，只有队列的RoutingKey与消息的RoutingKey
 *                                  完全一致，才会接收到消息。
 *  Routing之订阅模型-Topic：Topic类型的Exchange与Direct相比，把消息路由到不同的队列中。只不过Topic类型的Exchange可以让队列绑定在RoutingKey
 *                         的时候使用通配符，这种模型的RoutingKey一般都是由一个或多个单词组成，多个单词之间可以用“.”分割，例如“item.insert”
 *                         通配符： * 匹配不多不少恰好一个词，如audit.*只能匹配到audit.irs
 *                         # 匹配一个或多个词，如audit.#匹配到audit.irs或audit.irs.corporate等
 *
 *  使用场景：
 *  1.异步处理
 *  2.应用解耦
 *  3.流量削峰
 * @Date 2021/3/23 19:57
 * @Author maixy
 */
@Configuration
public class RabbitConfig {

    /**
     * 消息message
     */
    private final static String message = "topic.message";

    /**
     * 消息messages
     */
    private final static String messages = "topic.messages";

    //直连模式队列
    @Bean
    public Queue Query1() {
        return new Queue("hello1");
    }

    //work queues模式队列
    @Bean
    public Queue Query2() {
        return new Queue("hello2");
    }


    /***********************************Fanout模式*****************************************/
    //创建三个队列
    @Bean
    public Queue AMessage() {
        return new Queue("fanout.A");
    }

    @Bean
    public Queue BMessage() {
        return new Queue("fanout.B");
    }

    @Bean
    public Queue CMessage() {
        return new Queue("fanout.C");
    }

    //创建exchange,指定交换策略
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange("fanoutExchange");
    }

    //分别给三个队列指定exchange,这里使用了A,B,C三个队列绑定到Fanout交换机上面，参数就是创建队列的方法名或者创建交换机的方法名
    @Bean
    public Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(AMessage).to(fanoutExchange);
    }
    @Bean
    public Binding bindingExchangeB(Queue BMessage,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(BMessage).to(fanoutExchange);
    }
    @Bean
    public Binding bindingExchangeC(Queue CMessage,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(CMessage).to(fanoutExchange);
    }


    /***********************************Topic Exchange*****************************************/
    //创建两个Queue
    @Bean
    public Queue queueMessage() {
        return new Queue(RabbitConfig.message);
    }

    @Bean
    public Queue queueMessages() {
        return new Queue(RabbitConfig.messages);
    }

    //配置TopicExchange指定名称为topicExchange
    @Bean
    public TopicExchange exchange() {
        return new TopicExchange("topicExchange");
    }

    //给队列绑定exchange和routing_key
    @Bean
    public Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
    }

    @Bean
    public Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
    }
}
